namespace Angelus.Data.Linq.OracleClient
{
	using System;
    using System.Collections.Generic;
    using System.Data.OracleClient;
    using System.Data.DLinq.ProviderBase;

    /// <summary>
    /// 
    /// </summary>
    internal class OracleTypeSystemProvider : TypeSystemProvider
    {
        #region Fields

        private readonly Dictionary<int, OracleProviderType> _applicationTypes;

        #endregion

        #region Constructors

        internal OracleTypeSystemProvider()
        {
            this._applicationTypes = new Dictionary<int, OracleProviderType>();
        }

        #endregion

        #region Oracle Type System Provider Implementation

        /// <summary>
        /// 
        /// </summary>
        /// <param name="clrType"></param>
        /// <returns></returns>
        internal override ProviderType From(Type clrType)
        {
            return OracleProviderType.From(clrType);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        internal override ProviderType GetApplicationType(int index)
        {
            OracleProviderType provider;
            if (!this._applicationTypes.TryGetValue(index, out provider))
            {
                provider = OracleProviderType.CreateApplicationType(index);
                this._applicationTypes.Add(index, provider);
            }
            return provider;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        internal override int GetBoolValue(bool value)
        {
            return !value ? 0 : 1;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        internal override ProviderType MostPreciseTypeInFamily(ProviderType type)
        {
            OracleProviderType provider = (OracleProviderType) type;
            switch (provider.OracleType)
            {
                case OracleType.DateTime:
                case OracleType.Timestamp:
                case OracleType.TimestampLocal:
                case OracleType.TimestampWithTZ:
                    return this.From(typeof (DateTime));

                case OracleType.IntervalDayToSecond:
                case OracleType.IntervalYearToMonth:
                    return this.From(typeof (TimeSpan));


                case OracleType.Double:
                    return this.From(typeof (double));

                case OracleType.Float:
                    return this.From(typeof (decimal));

                case OracleType.Int16:
                    return this.From(typeof (Int16));

                case OracleType.Int32:
                    return this.From(typeof (Int32));

                case OracleType.UInt16:
                    return this.From(typeof (UInt16));

                case OracleType.UInt32:
                    return this.From(typeof (UInt32));
            }
            return type;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="text"></param>
        /// <returns></returns>
        internal override ProviderType Parse(string text)
        {
            return OracleProviderType.Parse(text);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="binary"></param>
        /// <param name="left"></param>
        /// <param name="right"></param>
        /// <returns></returns>
        internal override ProviderType PredictTypeForBinary(SqlNodeType binary, ProviderType left, ProviderType right)
        {
            return OracleTypePredictor.PredictTypeForBinary(this, binary, left, right);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="unary"></param>
        /// <param name="operand"></param>
        /// <returns></returns>
        internal override ProviderType PredictTypeForUnary(SqlNodeType unary, ProviderType operand)
        {
            return OracleTypePredictor.PredictTypeForUnary(this, unary, operand);
        }

        #endregion
    }
}